" File: 
"   transword.vim - look up a word in a dictionary
"
" Author: 
"   SangYang <upperyoung@foxmail.com>
"   inspired from 'transvim.vim' by Christian Habermann
"
" License: 
"   GNU General Public License 2 (GPL 2) or later
"
" Description:
"   This script looks up a word/phrase in a dictionary. User can press 
"   key-shortcuts to translate word under cursor, visually selected text
"   or to be asked for a word.
"
"   There are several possibilities to start a translation:
"     1) move cursor over word to be translated and press <Leader>tr/tf
"     2) visually select word to be translated and press <Leader>tr/tf
"     3) press <Leader>ta to be prompted for a word
"     Memory aid: tw = (T)ranslate (W)ord, ta = (T)ranslate (A)sk for word
"                 tf = (T)ranslate (F)uzzy match a word
"
"     Note: by default <Leader> is ',', so press ,tw, ,tf or ,ta to start
"           translation
"
" Installation:
"     To use this script copy it into your local plugin-directory
"     (Unix: ~./vim/plugin). After starting VIM this script is sourced
"     automatically.
"     In your .vimrc set path and filename of your dictionary, e.g.
"       let g:tr_dictionary = "~/.vim/dictionary/eng-ch.txt"
"     By default "grep" is used for searching, so you need it too.
"
" Dictionary:
"     Must be a plain ASCII-text file where each line contains one
"     word/phrase in language 1 and it's translation into language 2.
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

" allow user to avoid loading this plugin and prevent loading twice
if exists("g:tr_loaded_translate")
    finish
endif
let g:tr_loaded_translate = 1

" set the 'cpoptions' option to its Vim default value and restore it later.
" That will allow the use of line-continuation
let s:tr_save_cpo = &cpoptions
set cpoptions&vim

" if filename of dictionary is not set by user, take default
if !exists('g:tr_dictionary')
    let g:tr_dictionary = "~/.vim/ConciseOxfordEnglishDictionary.txt"
endif

" mapping setting
nmap <silent> <unique> <Leader>tw
    \ :call <SID>TransWord(expand("<cword>"))<CR>
vmap <silent> <unique> <Leader>tw
    \ y:call <SID>TransWord("<c-r>"")<CR>
map  <silent> <unique> <Leader>ta
    \ :call <SID>TransWordByAsk()<CR>
nmap <silent> <unique> <Leader>tf
    \ :call <SID>TransWordFuzzy(expand("<cword>"))<CR>
vmap <silent> <unique> <Leader>tf
    \ y:call <SID>TransWordFuzzy("<c-r>"")<CR>

" prompted user typed a word to translate
function <SID>TransWordByAsk()
    let str = input("Translate: ")
    echo ' '
    call <SID>TransWordFuzzy(str)
endfunction

" translate a word by strict match
function <SID>TransWord(str)
    let sys_str = system("grep -h -i -w \"^" . a:str . "\" " . g:tr_dictionary)
    if len(sys_str) == 0
        echoh WarningMsg
        echo a:str . ": No match word"
        echohl None
    endif

    let sys_list = split(sys_str, '\n\zs')
    for item in sys_list
        if match(item, "^" . a:str . "[^a-zA-Z]") != -1
            echomsg item
        endif
    endfor
endfunction

" Called to compare items relative the pos of substr in a list.
let s:temp_str = ''
function <SID>TransCompare(first, second)
    let first_idx =  stridx(tolower(a:first), tolower(s:temp_str))
    let second_idx =  stridx(tolower(a:second), tolower(s:temp_str))

    if first_idx == second_idx
        return 0
    elseif first_idx > second_idx
        return 1
    else
        return -1
    endif
endfunction

" translate a word by fuzzy match
function <SID>TransWordFuzzy(str)
    " Search single char is too slow for fuzzy match, so avoid this
    if strlen(a:str) < 2
        echoh WarningMsg
        echo a:str . ": too short length for fuzzy match, try '<Leader>tr'"
        echohl None
        return
    endif

    " Prior match the start of line is the word in dictionary.
    " then match others when the build-in Vim 'strgetchar()' function.
    let sys_str = system("grep -h -i \"^" . a:str . "\" " . g:tr_dictionary)
    let sys_str = sys_str . system("grep -h -i --max-count=100 \"^[^"
        \ . a:str[0] . '].*' . a:str . "\" " . g:tr_dictionary)

    " deal with these results and show
    if len(sys_str) == 0
        echoh WarningMsg
        echo a:str . ": No match word with fuzzy"
        echohl None
    else
        let s:temp_str = a:str
        let sys_list = split(sys_str, '\n')
        call sort(sys_list, "<SID>TransCompare")
        for item in sys_list
            echo item
        endfor
    endif
endfunction

" Restore 'cpoptions' option from Vim default value to previous value
let &cpoptions = s:tr_save_cpo
unlet s:tr_save_cpo
